using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Net;

namespace GCGM
{
	public partial class Form1 : Form
	{
		string mgsiUrl = @"https://bruce.isis.cclrc.ac.uk:18443/mgsi/rpc_soap.cgi";
		string fileServerUrl = @"https://bruce.isis.cclrc.ac.uk:28443/mgsi/filesvr.cgi";
		Mgsi.UdMgsi ud = new Mgsi.UdMgsi();
		
		string auth = "";
		List<Toler> toler = new List<Toler>();
		List<User> user = new List<User>();
		int dwnCounter = 0;

		public Form1()
		{
			InitializeComponent();
			//set the security policy to ignore the certificate error on bruce
			System.Net.ServicePointManager.CertificatePolicy = new MyPolicy();
			ud.Url = mgsiUrl;
		}



		#region Algorithm Choosing
		private void radCGM_CheckedChanged(object sender, EventArgs e)
		{
			algChanged();
		}

		private void algChanged()
		{
			unlock_Controls();
			if (radCGM.Checked)
			{
				label7.Text = radCGM.Text;
				toolStripStatusLabel1.Text = "Conjugate Gradient Method (CGM)";
			}
			else
			{
				label7.Text = radQN.Text;
				toolStripStatusLabel1.Text = "Quasi-Newton (QN)";
			}
		}

		private void radQN_CheckedChanged(object sender, EventArgs e)
		{
			algChanged();
		}
		#endregion

		#region Control locking and unlocking
		private void lock_Controls()
		{
			#region Labels
			label17.Enabled = false;
            label19.Enabled = false;
            label1.Enabled = false;
            label5.Enabled = false;
            label6.Enabled = false;
            label8.Enabled = false;
            label20.Enabled = false;
            label9.Enabled = false;
            label18.Enabled = false;
			label15.Enabled = false;
			#endregion

			#region Text, Group and List Boxes
			txtCgmExe.Enabled = false;
			txtInputFolder.Enabled = false;
			txtJobName.Enabled = false;
			txtOutputName.Enabled = false;
			txtN.Enabled = false;
			txtNruns.Enabled = false;
			txtNumPkg.Enabled = false;
			//txtPassword.Enabled = false;
			txtRaw.Enabled = false;
			txtSeed.Enabled = false;
			//txtTolStart.Enabled = false;
			//txtTolStep.Enabled = false;
			//txtTolStop.Enabled = false;
			//txtUsername.Enabled = false;
			txtZmat.Enabled = false;
			//lstTol.Enabled = false;
			grpTol.Enabled = false;
			grpLogin.Enabled = false;
			grpDownload.Enabled = false;
			#endregion

			#region Buttons
			radCGM.Enabled = false;
			radQN.Enabled = false;
			radFixed.Enabled = false;
			radStepped.Enabled = false;
			butAdd.Enabled = false;
			butCGM.Enabled = false;
			butInput.Enabled = false;
			butRaw.Enabled = false;
			butRemove.Enabled = false;
			butZmat.Enabled = false;
			cmdSubmit.Enabled = false;
			cmdDownload.Enabled = false;
			#endregion

		}

		private void unlock_Controls()
		{
			#region Labels
			label17.Enabled = true;
			label19.Enabled = true;
			label1.Enabled = true;
			label5.Enabled = true;
			label6.Enabled = true;
			label8.Enabled = true;
			label20.Enabled = true;
			label9.Enabled = true;
			label18.Enabled = true;
			label15.Enabled = true;
			#endregion

			#region Text, Group and List Boxes
			txtCgmExe.Enabled = true;
			txtInputFolder.Enabled = true;
			txtJobName.Enabled = true;
			txtOutputName.Enabled = true;
			txtN.Enabled = true;
			txtNruns.Enabled = true;
			txtNumPkg.Enabled = true;
			//txtPassword.Enabled = true;
			txtRaw.Enabled = true;
			txtSeed.Enabled = true;
			//txtTolStart.Enabled = true;
			//txtTolStep.Enabled = true;
			//txtTolStop.Enabled = true;
			//txtUsername.Enabled = true;
			txtZmat.Enabled = true;
			//lstTol.Enabled = true;
			grpTol.Enabled = true;
			grpLogin.Enabled = true;
			grpDownload.Enabled = true;
			#endregion

			#region Buttons
			radCGM.Enabled = true;
			radQN.Enabled = true;
			radFixed.Enabled = true;
			radStepped.Enabled = true;
			butAdd.Enabled = true;
			butCGM.Enabled = true;
			butInput.Enabled = true;
			butRaw.Enabled = true;
			butRemove.Enabled = true;
			butZmat.Enabled = true;
			cmdSubmit.Enabled = true;
			cmdDownload.Enabled = true;
			#endregion
		}
		#endregion

		#region Creating Input Files
		private void createInputFiles(List<double> tols, List<string> paramfiles)
		{
			foreach (double tol in tols)
			{
				try
				{
					writeFiles(paramfiles, tol);
				}
				catch (Exception wfe)
				{
					MessageBox.Show("Error: " + wfe.Message, "Error in write files", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}

			}// End Tolerances
		}

		private void writeFiles(List<string> files, double tol)
		{
			string folder = txtInputFolder.Text + "\\" + txtJobName.Text;

			if (!Directory.Exists(folder))
			{
				Directory.CreateDirectory(folder);
			}

			int seed = int.Parse(txtSeed.Text);
			int nruns = (int.Parse(txtNruns.Text) / int.Parse(txtNumPkg.Text));

			for (int i = 1; i <= (int.Parse(txtNumPkg.Text)); i++)
			{
				string name = createString(seed, tol);
				StreamWriter sw = new StreamWriter(folder + "\\" + name);

				string zMat = "Input\\" + Path.GetFileName(txtZmat.Text);
				string raw = "Input\\" + Path.GetFileName(txtRaw.Text);

				sw.WriteLine(seed);
				sw.WriteLine(tol);
				sw.WriteLine(nruns);
				sw.WriteLine(txtN.Text);
				sw.WriteLine(zMat);
				sw.WriteLine(raw);
				sw.WriteLine(txtJobName.Text + "_" + txtOutputName.Text);

				sw.Close();
				seed++;

				files.Add(folder + "\\" + name);
			}
		}

		private string createString(int seed, double tol)
		{
			string tolS = tol.ToString();
			if (tolS.Contains("e") == false)
			{
				tolS = tolS.Replace(".", "-");
			}

			string seedS = seed.ToString();

			string s = "tol" + tolS + "_seed" + seedS + ".txt";

			return s;
		}

		private void createTolArray(List<double> tols)
		{
			double tolStart = double.Parse(txtTolStart.Text);
			double tolStop = double.Parse(txtTolStop.Text);
			double tolStep = double.Parse(txtTolStep.Text);
			double currentTol = tolStart;
			while (currentTol <= tolStop)
			{
				tols.Add(currentTol);
				currentTol = currentTol + tolStep;
			}
		}
		#endregion

		#region Validation
		private void validateInput()
		{
			toolStripStatusLabel1.Text = "Validating input...";

			int seed;
			double tolStart;
			double tolStop;
			double tolStep;
			int nruns;
			int ndim;
			int numpkg;

			#region builpkg
			string buildPkgLocation = Application.StartupPath + @"\buildpkg.exe";
			if (!File.Exists(buildPkgLocation))
			{
				throw new Exception("Could not find: " + buildPkgLocation);
			}
			#endregion

			#region Seed
			if (txtSeed.Text == "")
			{
				throw new Exception("You must not leave the seed field blank");
			}
			else
			{
				try
				{
					seed = int.Parse(txtSeed.Text);
				}
				catch (Exception)
				{
					throw new Exception("Seed must be numeric");
				}
			}

			if (seed == 0.0)
			{
				throw new Exception("The seed cannot be zero");
			}
			#endregion

			#region Tolerance
			if ((radFixed.Checked == true) && (lstTol.Items.Count == 0))
			{
				throw new Exception("You must enter some values for the tolerance");
			}
			else if (radStepped.Checked == true)
			{
				if (txtTolStart.Text == "" || txtTolStop.Text == "" || txtTolStep.Text == "")
				{
					throw new Exception("You must not leave any tolerance fields blank");
				}
				else
				{
					try
					{
						tolStart = double.Parse(txtTolStart.Text);
						tolStop = double.Parse(txtTolStop.Text);
						tolStep = double.Parse(txtTolStep.Text);
					}
					catch (Exception)
					{
						throw new Exception("The values must be numeric");
					}


					if (tolStart > tolStop)
					{
						throw new Exception("Start tolerance is bigger than the stop tolerance");
					}
					else if (tolStart == 0.0)
					{
						throw new Exception("Starting tolerance is zero");
					}
					else if (tolStop == 0.0)
					{
						throw new Exception("Stop tolerance is zero");
					}
					else if (tolStep == 0.0)
					{
						throw new Exception("Tolerance step is zero");
					}
					else if (tolStep >= 5)
					{
						throw new Exception("Tolerance is too high");
					}
				}
			}
			#endregion

			#region Nruns, N, NumPkg
			if (txtNruns.Text == "")
			{
				throw new Exception("Please fill in the Nruns field");
			}
			else
			{
				try
				{
					nruns = int.Parse(txtNruns.Text);
				}
				catch (Exception)
				{
					throw new Exception("Nruns must be numeric");
				}

				if (nruns == 0)
				{
					throw new Exception("Nruns cannot be zero");
				}
			}

			if (txtN.Text == "")
			{
				throw new Exception("Please fill in the Number of Dimensions (N) field");
			}
			else
			{
				try
				{
					ndim = int.Parse(txtN.Text);
				}
				catch (Exception)
				{
					throw new Exception("N must be numeric");
				}

				if (ndim == 0)
				{
					throw new Exception("N cannot be zero");
				}
			}

			if (txtNumPkg.Text == "")
			{
				throw new Exception("Please fill in the Number of Packages field");
			}
			else
			{
				try
				{
					numpkg = int.Parse(txtNumPkg.Text);
				}
				catch (Exception)
				{
					throw new Exception("Number of Packages must be numeric");
				}

				if (numpkg == 0)
				{
					throw new Exception("Number of Packages cannot be zero");
				}

				List<int> factors = new List<int>();
				Factor(factors, nruns);
				if (factors.Contains(numpkg) == false)
				{
					throw new Exception("Number of Packages must be a factor of the total number of runs (Nruns)");
				}

			}
			#endregion

			#region Zmatrix, Raw data, Job Name, Input Checking and Exe
			if (txtZmat.Text == "" || txtRaw.Text == "" || txtJobName.Text == "" || txtInputFolder.Text == "" || txtCgmExe.Text == "")
			{
				throw new Exception("You must not leave any fields blank\nPlease double check you have filled all the fields in.");
			}

			if (!File.Exists(txtZmat.Text))
			{
				throw new Exception("Could not find specified Z-Matrix");
			}
			if (!File.Exists(txtRaw.Text))
			{
				throw new Exception("Could not find specified Raw Data");
			}
			if (!File.Exists(txtCgmExe.Text))
			{
				throw new Exception("Could not find the specified Exe file");
			}
			if (!Directory.Exists(txtInputFolder.Text))
			{
				DialogResult d = MessageBox.Show("The directory " + txtInputFolder.Text + " does not exist\nWould you like to create it?", "Save Director", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
				if (d == DialogResult.OK)
				{
					Directory.CreateDirectory(txtInputFolder.Text);
				}
				else if (d == DialogResult.Cancel)
				{
					txtInputFolder.Text = "";
					throw new Exception("");
				}
			}
			if (Directory.Exists(txtInputFolder.Text + "\\" + txtJobName.Text))
			{
				throw new Exception("The directory " + txtInputFolder.Text + "\\" + txtJobName.Text + " already exists, please specify a different job name");
			}
			#endregion
		}

		private void validateDlInput()
		{
			toolStripStatusLabel1.Text = "Validating Download...";

			int cutoff;
			int jobid;

			#region SaveDir

			if (!Directory.Exists(txtSaveDir.Text))
			{
				
				DialogResult d = MessageBox.Show("The directory " + txtSaveDir.Text + " does not exist\nWould you like to create it?", "Save Director", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
				if (d == DialogResult.OK)
				{
					Directory.CreateDirectory(txtSaveDir.Text);
				}
				else if (d == DialogResult.Cancel)
				{
					txtSaveDir.Text = "";
					throw new Exception("");
				}
			}

			#endregion

			if (radUser.Checked)
			{
				#region User
				if (lstJobs.Items.Count == 0)
				{
					throw new Exception("Please enter at least one job to retrieve");
				}
				foreach (ListViewItem l in lstJobs.Items)
				{
					if (l.SubItems[3].Text == "")
					{
						throw new Exception("Please enter a cut off in the list of jobs");
					}
					else
					{
						try
						{
							int.Parse(l.SubItems[3].Text);
						}
						catch (Exception)
						{
							throw new Exception("The cut off must be numeric");
						}
					}
				}
				#endregion
			}
			else if (radJobID.Checked)
			{
				#region JobID
				if (txtJobId.Text == "")
				{
					throw new Exception("Please enter a job ID number");
				}
				else
				{
					try
					{
						jobid = int.Parse(txtJobId.Text);
					}
					catch (Exception)
					{
						txtJobId.Text = "";
						throw new Exception("Job ID must be numeric");
					}

					if (jobid == 0)
					{
						throw new Exception("The job ID number must be nonzero");
					}
				}
				#endregion

				#region CutOff
				if (txtCutOff.Text == "")
				{
					throw new Exception("Please enter a cutoff!");
				}
				else
				{
					try
					{
						cutoff = int.Parse(txtCutOff.Text);
					}
					catch (Exception)
					{
						throw new Exception("Cutoff must be numeric");
					}

					if (cutoff == 0)
					{
						throw new Exception("Cutoff cannot be zero");
					}
				}
				#endregion
			}

		}

		private void Factor(List<int> factors, int nruns)
		{
			for (int i = 1; i <= nruns; i++)
			{
				if (Math.IEEERemainder((double)nruns, (double)i) == 0.0)
				{
					factors.Add(i);
				}
			}
		}
		#endregion

		#region Job Submitting
		private void cmdSubmit_Click(object sender, EventArgs e)
		{
			lock_Controls();
			toolStripProgressBar1.Value = 0;

			/************************************************/
			/*				Validate entry					*/
			/************************************************/
			try
			{
				validateInput();
			}
			catch (Exception excep)
			{
				if (excep.Message == "")
				{
					unlock_Controls();
					toolStripStatusLabel1.Text = "Conjugate Gradient Method";
					return;
				}
				MessageBox.Show("Error: " + excep.Message, "Error in Input", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}

			// Log input
			log();


			/************************************************/
			/*				Generate Arrays					*/
			/************************************************/

			List<string> paramfiles = new List<string>();

			#region Generate Arrays
			if (radStepped.Checked)	//Stepped
			{
				List<double> tols = new List<double>();

				//define array of Tolerances   
				createTolArray(tols);

				/************************************************/
				/*			Generate Input Files				*/
				/************************************************/
				createInputFiles(tols, paramfiles);
			}
			else //Fixed
			{
				foreach (Toler tol in toler)
				{
					try
					{
						writeFiles(paramfiles, tol.Tolerance);
					}
					catch (Exception wfe)
					{
						MessageBox.Show("Error: " + wfe.Message, "Error in write files", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}
				}//End Tolerances
			}// end stepped/fixed
			#endregion


			/************************************************/
			/*					Grid Stuff					*/
			/************************************************/

			toolStripStatusLabel1.Text = "Creating Grid Object...";
			this.Refresh();


			toolStripStatusLabel1.Text = "Grid Object created!";
			this.Refresh();

			// Logging into the grid
			auth = loginToGrid();
			if (auth == null)
			{
				unlock_Controls();
				return; 
			}

			// Method used to set up the grid
			createGridInfo(paramfiles);

			MessageBox.Show("Sent!");

			unlock_Controls();
			toolStripProgressBar1.Value = 0;
			toolStripProgressBar1.Visible = false;
			toolStripStatusLabel1.Text = "Conjugate Gradient Method (CGM)";
			this.Refresh();
		}

		private void createGridInfo(List<string> paramfiles)
		{
			logInTimer.Start();

			toolStripProgressBar1.Visible = true;
			toolStripProgressBar1.Maximum = 100;
			toolStripProgressBar1.Minimum = 0;
			toolStripProgressBar1.Value = 0;

			toolStripStatusLabel1.Text = "Creating job";
			toolStripProgressBar1.Value = toolStripProgressBar1.Value + 1;
			this.Refresh();

			#region ud.getApplicationByName and ud.getProgramByName
			Mgsi.Application app = null;
			Mgsi.Program prog = null;
			try
			{
				app = ud.getApplicationByName(auth, "Dev_HMC");
			}
			catch (Exception appe)
			{
				MessageBox.Show("Error: " + appe.Message, "Error in ud.getApplicationByName", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			try
			{
				prog = ud.getProgramByName(auth, "Dev_HMC");
			}
			catch (Exception proge)
			{
				MessageBox.Show("Error: " + proge.Message, "Error in ud.getProgramByName", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			#region Create job
			Mgsi.Job job = new Mgsi.Job();

			job.annotation = txtNruns.Text;
			job.description = txtJobName.Text;
			job.state_id = 1;
			job.priority = 10;
			job.application_gid = app.application_gid;

			try
			{
				job.job_gid = ud.createJob(auth, job);
			}
			catch (Exception jobe)
			{
				MessageBox.Show("Error: " + jobe.Message, "Error in ud.createJob", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			toolStripStatusLabel1.Text = "Creating jobstep";
			toolStripProgressBar1.Value = toolStripProgressBar1.Value + 1;
			this.Refresh();

			#region Create jobstep
			Mgsi.JobStep jobstep = new Mgsi.JobStep();
			jobstep.job_gid = job.job_gid;
			jobstep.state_id = 1;
			jobstep.program_gid = prog.program_gid;
			jobstep.num_results = 1;
			jobstep.max_errors = 5;
			jobstep.max_concurrent = 1;
			jobstep.wu_cpu_timeout = 36000;
			jobstep.wu_clock_timeout = 36000;

			try
			{
				jobstep.job_step_gid = ud.createJobStep(auth, jobstep);
			}
			catch (Exception jobstepe)
			{
				MessageBox.Show("Error: " + jobstepe.Message, "Error in ud.createJobStep", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			try
			{
				jobstep = ud.getJobStep(auth, jobstep.job_step_gid);
			}
			catch (Exception jstepe)
			{
				MessageBox.Show("Error: " + jstepe.Message, "Error in ud.getJobStep", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			toolStripStatusLabel1.Text = "Creating dataset1";
			toolStripProgressBar1.Value = toolStripProgressBar1.Value + 1;
			this.Refresh();

			#region Create dataset1
			Mgsi.DataSet dataset1 = new Mgsi.DataSet();
			dataset1.data_set_name = txtJobName.Text + "_ds1_" + DateTime.Now.Ticks;
			dataset1.persistency = 50;
			dataset1.job_gid = job.job_gid;
			//dataset1.job_step_gid = jobstep.job_step_gid;
			try
			{
				dataset1.data_set_gid = ud.createDataSet(auth, dataset1);
			}
			catch (Exception ds1e)
			{
				MessageBox.Show("Error: " + ds1e.Message, "Error in ud.createDataSet (DataSet1)", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			toolStripStatusLabel1.Text = "Creating dataset2";
			toolStripProgressBar1.Value = toolStripProgressBar1.Value + 1;
			this.Refresh();

			#region Create dataset2
			Mgsi.DataSet dataset2 = new Mgsi.DataSet();
			dataset2.data_set_name = txtJobName.Text + "_ds2_" + DateTime.Now.Ticks;
			dataset2.persistency = 50;
			dataset2.job_gid = job.job_gid;
			//dataset2.job_step_gid = jobstep.job_step_gid;
			try
			{
				dataset2.data_set_gid = ud.createDataSet(auth, dataset2);
			}
			catch (Exception ds2e)
			{
				MessageBox.Show("Error: " + ds2e.Message, "Error in ud.createDataSet (DataSet2)", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			FileTransfer.FileTransfer ft = new FileTransfer.FileTransfer();

			toolStripStatusLabel1.Text = "Creating data items";
			toolStripProgressBar1.Value = toolStripProgressBar1.Value + 1;
			this.Refresh();

			#region Create data items
			//need to copy the zmatrix and raw file into the same folder as the params files
			string exampleParamfile = paramfiles[0];
			string tempDir = Path.GetDirectoryName(exampleParamfile);
			string inputFolder = tempDir + "\\Input";
			string outputDir = tempDir + @"\Output\ZfuncMolecule\" + txtJobName.Text + "_" + txtOutputName.Text;

			/*string outputFamot = tempDir + @"\Output\ZfuncMolecule\Famot";
			string outputChloro = tempDir + @"\Output\ZfuncMolecule\Chloro";
			string outputCap = tempDir + @"\Output\ZfuncMolecule\Cap";*/

			#region Input/Output folders
			try
			{
				Directory.CreateDirectory(inputFolder);
			}
			catch (Exception ife)
			{
				MessageBox.Show("Error: " + ife.Message, "Error in creating input directory", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			try
			{
				Directory.CreateDirectory(outputDir);
			}
			catch (Exception ofe)
			{
				MessageBox.Show("Error: " + ofe.Message, "Error in creating output directory", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}

			/*Directory.CreateDirectory(outputFamot);
			Directory.CreateDirectory(outputChloro);
			Directory.CreateDirectory(outputCap);*/

			string pkgStringOutput = outputDir + "\\d.imag";

			/*string pkgStringFamot = outputFamot + "\\a.imag";
			string pkgStringChloro = outputChloro + "\\b.imag";
			string pkgStringCap = outputCap + "\\c.imag";*/

			FileStream fs = null;
			try
			{
				fs = File.Create(pkgStringOutput);
			}
			catch (Exception fse)
			{
				MessageBox.Show("Error: " + fse.Message, "Error in creating imag file", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			fs.Close();

			/*fs = File.Create(pkgStringFamot);
			fs.Close();
			fs = File.Create(pkgStringChloro);
			fs.Close();
			fs = File.Create(pkgStringCap);
			fs.Close();*/
			#endregion

			#region Copying necessary files
			string zmatInput = inputFolder + "\\" + Path.GetFileName(txtZmat.Text);
			string rawInput = inputFolder + "\\" + Path.GetFileName(txtRaw.Text);
			try
			{
				File.Copy(txtZmat.Text, zmatInput);
				File.Copy(txtRaw.Text, rawInput);
			}
			catch (Exception cpye)
			{
				MessageBox.Show("Error: " + cpye.Message, "Error in copying Zmatrix and Raw files", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}

			//copy hmc from where it is to tempDir
			//use it's new location as the hmc.exe file
			string tempCGMLocation = tempDir + "\\" + Path.GetFileName(txtCgmExe.Text);
			try
			{
				File.Copy(txtCgmExe.Text, tempCGMLocation);
			}
			catch (Exception cpye)
			{
				MessageBox.Show("Error: " + cpye.Message, "Error in copying HMC.exe file", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}

			//copy builpkg from App.startpath to tempDir
			string tempBuildPkgLocation = tempDir + "\\buildpkg.exe";
			try
			{
				File.Copy(Application.StartupPath + "\\buildpkg.exe", tempBuildPkgLocation);
			}
			catch (Exception cpye)
			{
				MessageBox.Show("Error: " + cpye.Message, "Error in copying buildpkg.exe", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			#region Build package
			string arguments = "-p -f -m\".$\" -n cgm.tar \"" + tempCGMLocation + "\"" + " " + "\"" + zmatInput + "\"" + " " + "\"" + rawInput + "\"" + " " + "\"" + pkgStringOutput + "\"";
			//string arguments = "-p -f -m\".$\" -n cgm.tar \"" + tempCGMLocation + "\"" + " " + "\"" + zmatInput + "\"" + " " + "\"" + rawInput + "\"" + " " + "\"" + pkgStringFamot + "\"" + " " + "\"" + pkgStringChloro + "\"" + " " + "\"" + pkgStringCap + "\"";
			arguments = MakeArgumentsRelative(arguments, tempBuildPkgLocation);
			// run buildpkg
			try
			{
				buildPkg(arguments, tempBuildPkgLocation);
			}
			catch (Exception bpkge)
			{
				MessageBox.Show("Error: " + bpkge.Message, "Error in building the package", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			// cgm.tar now exists
			#endregion

			#endregion

			toolStripStatusLabel1.Text = "Uploading data...";
			toolStripProgressBar1.Value = toolStripProgressBar1.Value + 1;
			this.Refresh();

			FileTransfer.UploadData result;

			#region Upload data
			try
			{
				result = ft.uploadFile(auth, tempDir + "\\cgm.tar", fileServerUrl);
			}
			catch (Exception upe)
			{
				MessageBox.Show("Error: " + upe.Message, "Error uploading dataset1", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			#region Create data1
			Mgsi.Data cgmdata = new Mgsi.Data();
			cgmdata.data_set_gid = dataset1.data_set_gid;
			cgmdata.index = 1;
			cgmdata.file_hash = result.hash;
			cgmdata.file_size = long.Parse(result.size);
			try
			{
				ud.createData(auth, cgmdata);
			}
			catch (Exception cde)
			{
				MessageBox.Show("Error: " + cde.Message, "Error in ud.createData", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			#region Create data2[]
			Mgsi.Data[] dataarray = new Mgsi.Data[paramfiles.Count];
			int counter = 0;

			int startValue = toolStripProgressBar1.Value;
			int percent = toolStripProgressBar1.Maximum - startValue;

			foreach (string file in paramfiles)
			{
				string tempParam;
				if (radCGM.Checked)
				{
					tempParam = inputFolder + "\\params_cgm.txt";
				}
				else
				{
					tempParam = inputFolder + "\\params_qn.txt";
				}
				try
				{
					File.Copy(file, tempParam, true);
				}
				catch (Exception cpye)
				{
					MessageBox.Show("Error: " + cpye.Message, "Error in copying input files to params_cgm/params_qn", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}

				arguments = "-p -f -m\".$\" -n datafile_" + counter + ".tar \"" + tempParam + "\"";
				//run buildpkg
				arguments = MakeArgumentsRelative(arguments, tempBuildPkgLocation);
				try
				{
					buildPkg(arguments, tempBuildPkgLocation);
				}
				catch (Exception bpkge)
				{
					MessageBox.Show("Error: " + bpkge.Message, "Error in building package", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}

				try
				{
					result = ft.uploadFile(auth, tempDir + "\\datafile_" + counter + ".tar", fileServerUrl);
				}
				catch (Exception upe)
				{
					MessageBox.Show("Error: " + upe.Message, "Error in uploading dataset2", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}

				double percentOfFiles = (((double)counter / (double)paramfiles.Count) * 100);
				toolStripProgressBar1.Value = ((int)(((double)percent / 100.0) * percentOfFiles)) + startValue;
				this.Refresh();

				Mgsi.Data data = new Mgsi.Data();
				data.data_set_gid = dataset2.data_set_gid;
				data.index = counter + 1;
				data.file_hash = result.hash;
				data.file_size = long.Parse(result.size);

				dataarray[counter] = data;
				counter++;
			}

			try
			{
				ud.createDatasAsync(auth, dataarray);
				toolStripStatusLabel1.Text = "Waiting for data to return";

				Mgsi.DataFilter df = new GCGM.Mgsi.DataFilter();
				df.data_set_gid_match = new string[] { dataset2.data_set_gid };
				df.index_min = dataarray.Length;
				df.index_test = "GE";
				Mgsi.DataArrayRange dar;
				while (true)
				{
					dar = ud.getDatas(auth, df, "index asc", 0, -1);
					if (dar.total >= 1)
					{
						break;
					}
					System.Threading.Thread.Sleep(5000);
				}	
			}
			catch (Exception ude)
			{
				MessageBox.Show("Error: " + ude.Message, "Error in Uploading", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			string[] dsgid = new string[] { dataset1.data_set_gid, dataset2.data_set_gid };
			Mgsi.CreateWorkunitsFromDataSetsOptions options = new Mgsi.CreateWorkunitsFromDataSetsOptions();
			options.creation_mode = 0;

			#region Create Workunits
			try
			{
				ud.createWorkunitsFromDataSetsAsync(auth, jobstep.job_step_gid, dsgid, options);
			}
			catch (Exception wrke)
			{
				MessageBox.Show("Error: " + wrke.Message, "Error in ud.createWorkUnitsFromDataSetsAsync", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			#region Updating jobstep
			try
			{
				jobstep = ud.getJobStep(auth, jobstep.job_step_gid);
			}
			catch (Exception jstepe)
			{
				MessageBox.Show("Error: " + jstepe.Message, "Error in getting jobstep", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}

			jobstep.state_id = 4;

			try
			{
				ud.updateJobStep(auth, jobstep);
			}
			catch (Exception ujstepe)
			{
				MessageBox.Show("Error: " + ujstepe.Message, "Error in updating jobstep", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			#endregion

			logInTimer.Stop();
		}

		private static void buildPkg(string arguments, string buildPkgLocation)
		{
			Process buildpkgProcess = new Process();
			buildpkgProcess.StartInfo.Arguments = arguments;
			buildpkgProcess.StartInfo.FileName = buildPkgLocation;
			buildpkgProcess.StartInfo.UseShellExecute = false;
			buildpkgProcess.StartInfo.RedirectStandardError = true;
			buildpkgProcess.StartInfo.RedirectStandardOutput = true;
			buildpkgProcess.StartInfo.CreateNoWindow = true;
			buildpkgProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(buildPkgLocation);

			buildpkgProcess.Start();
			string error = buildpkgProcess.StandardError.ReadToEnd();
			string output = buildpkgProcess.StandardOutput.ReadToEnd();
			buildpkgProcess.WaitForExit();
		}

		private static string MakeArgumentsRelative(string arguments, string buildpkgLocation)
		{
			string buildpkgFolder = Path.GetDirectoryName(buildpkgLocation);
			arguments = arguments.Replace(buildpkgFolder, ".");
			return arguments;
		}
		#endregion

		#region Submit events
		private void butZmat_Click(object sender, EventArgs e)
		{
			zmatOpenDialog.InitialDirectory = Directory.GetCurrentDirectory();
			zmatOpenDialog.Title = "Open a .zmatrix file";
			zmatOpenDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
			zmatOpenDialog.FileName = ".txt";

			if (zmatOpenDialog.ShowDialog() == DialogResult.OK)
			{
				txtZmat.Text = zmatOpenDialog.FileName;
			}
		}

		private void butRaw_Click(object sender, EventArgs e)
		{
			//rawOpenDialog.InitialDirectory = Directory.GetCurrentDirectory();
			rawOpenDialog.Title = "Open a .txt file";
			rawOpenDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
			rawOpenDialog.FileName = ".txt";

			if (rawOpenDialog.ShowDialog() == DialogResult.OK)
			{
				txtRaw.Text = rawOpenDialog.FileName;
			}
		}

		private void butCGM_Click(object sender, EventArgs e)
		{
			cgmOpenDialog.Title = "Open a .exe file";
			cgmOpenDialog.Filter = "Exe files (*.exe)|*.exe|All files (*.*)|*.*";
			cgmOpenDialog.FileName = ".exe";

			if (cgmOpenDialog.ShowDialog() == DialogResult.OK)
			{
				txtCgmExe.Text = cgmOpenDialog.FileName;
			}
		}

		private void butInput_Click(object sender, EventArgs e)
		{
			if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
			{
				txtInputFolder.Text = folderBrowserDialog1.SelectedPath;
			}
		}

		private void radStepped_CheckedChanged(object sender, EventArgs e)
		{
			radioButtonsChanged();
		}

		private void radFixed_CheckedChanged(object sender, EventArgs e)
		{
			radioButtonsChanged();
		}

		private void radioButtonsChanged()
		{
			if (radStepped.Checked)
			{
				grpStepped.Enabled = true;
				grpFixed.Enabled = false;
			}
			else
			{
				grpStepped.Enabled = false;
				grpFixed.Enabled = true;
			}
		}

		private void butAdd_Click(object sender, EventArgs e)
		{
			Tolerance tol = new Tolerance(ref lstTol, ref toler);
			tol.getTol();
		}

		private void butRemove_Click(object sender, EventArgs e)
		{
			int nremoved = 0;
			int whichone = 0;

			foreach (int index in lstTol.SelectedIndices)
			{
				whichone = index - nremoved;
				try
				{
					toler.Remove(toler[whichone]);
				}
				catch (Exception exception)
				{
					MessageBox.Show("Error: " + exception.Message, "Error in removing tolerances from list", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}
				nremoved++;
			}

			while (lstTol.SelectedItems.Count != 0)
			{
				try
				{
					lstTol.Items.RemoveAt(lstTol.SelectedIndices[0]);
				}
				catch (Exception exception)
				{
					MessageBox.Show("Error: " + exception.Message, "Error in removing tolerances", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}
			}
		}
		#endregion

		#region Job Retrieval
		private void cmdDownload_Click(object sender, EventArgs e)
		{
			lock_Controls();

			try
			{
				validateDlInput();
			}
			catch (Exception excep)
			{
				if (excep.Message == "")
				{
					unlock_Controls();
					toolStripStatusLabel1.Text = "Conjugate Gradient Method";
					return;
				}
				MessageBox.Show("Error: " + excep.Message, "Error in Download Input", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				toolStripStatusLabel1.Text = "Conjugate Gradient Method";
				return;
			}

			logInTimer.Start();

			//check username and password are not null
			toolStripStatusLabel1.Text = "Creating Grid Object...";
			this.Refresh();
			ud.Url = mgsiUrl;
			toolStripStatusLabel1.Text = "Grid Object created!";
			this.Refresh();

			//set the security policy to ignore the certificate error on bruce
			System.Net.ServicePointManager.CertificatePolicy = new MyPolicy();

			// Logging into the grid
			auth = loginToGrid();
			if (auth == null)
			{
				unlock_Controls();
				return;
			}


			//we are logged in, get the job using the jobid
			//this needs a try as the id may not be a real job
			Mgsi.Job job = new Mgsi.Job();
			if (radJobID.Checked)
			{
				dwnCounter = 1;

				try
				{
					job = ud.getJobById(auth, int.Parse(txtJobId.Text));
				}
				catch (Exception)
				{
					MessageBox.Show("Error retrieving job " + txtJobId.Text + "\nPlease check that it is a valid job ID", "Error in retrieval", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}

				dwnGridInfo(auth, ud, job);				
			}
			else if (radUser.Checked)
			{
				dwnCounter = 0;

				foreach (User u in user)
				{
					dwnCounter++;
					try
					{
						job = ud.getJobById(auth, u.jobId);
					}
					catch (Exception)
					{
						MessageBox.Show("Error retrieving job " + u.jobId + "\nPlease check that it is a valid job", "Error in retrieval", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}
					dwnGridInfo(auth, ud, job);
				}
			}

			MessageBox.Show("Received!");

			unlock_Controls();

			toolStripStatusLabel1.Text = "Conjugate Gradient Method (CGM)";
			toolStripProgressBar1.Value = 0;
			toolStripProgressBar1.Visible = false;
			this.Refresh();

			logInTimer.Stop();			
		}

		private void dwnGridInfo(string auth, Mgsi.UdMgsi ud, Mgsi.Job job)
		{
			try
			{
				string appName = ud.getApplication(auth, job.application_gid).application_name;
				if (appName != "Dev_HMC")
				{
					throw new Exception("Application is not the HMC application 'Dev_HMC'");
				}
			}
			catch (Exception appne)
			{
				MessageBox.Show("Error: " + appne.Message, "Error: Wrong Application", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}

			Mgsi.JobStatus status = ud.getJobStatus(auth, job.job_gid);

			if (job.state_id == 1)
			{
				MessageBox.Show("The job has not finished yet: " + status.completed_percent + "% complete", "State: Incomplete", MessageBoxButtons.OK, MessageBoxIcon.Information);
				unlock_Controls();
				return;
			}
			else if (job.state_id == 2)
			{
				MessageBox.Show("The job is suspended so cannot complete", "State: Suspended", MessageBoxButtons.OK, MessageBoxIcon.Information);
				unlock_Controls();
				return;
			}
			else if (job.state_id == 4)
			{
				MessageBox.Show("The job has failed", "State: Failed", MessageBoxButtons.OK, MessageBoxIcon.Information);
				unlock_Controls();
				return;
			}
			else if (job.state_id == 3)// completed
			{
				//get the results
				Mgsi.ResultFilter resFilter = new Mgsi.ResultFilter();
				resFilter.job_gid_match = new string[1] { job.job_gid };
				Mgsi.ResultArrayRange rar;
				try
				{
					rar = ud.getResults(auth, resFilter, "workunit_index asc", 0, -1);
				}
				catch (Exception rese)
				{
					MessageBox.Show("Error: " + rese.Message, "Error in ud.getResults by workunit index", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}
				//make a folder to work in
				string tempDirName = txtSaveDir.Text + @"\" + job.description + "_" + DateTime.Now.Ticks;

				FileTransfer.FileTransfer ft = new FileTransfer.FileTransfer();

				Directory.CreateDirectory(tempDirName);
				int counter = 0;
				double percent = 0.0;
				int d;
				List<string> folders = new List<string>();
				toolStripProgressBar1.Visible = true;
				toolStripProgressBar1.Maximum = 100;
				toolStripProgressBar1.Minimum = 0;
				toolStripProgressBar1.Value = 0;
				foreach (Mgsi.Result r in rar.records)
				{
					counter++;
					percent = percent + 1.0;
					string tempFile = tempDirName + "\\" + counter + ".tar";
					string tempFolder = tempDirName + "\\" + counter;
					folders.Add(tempFolder);
					try
					{
						ft.downloadResult(r.result_hash, auth, tempFile, fileServerUrl);
					}catch(Exception dre)
					{
						MessageBox.Show("Error: " + dre.Message, "Error in downloadResult", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}
					try
					{
						ft.untar(tempFile, tempFolder);
					}
					catch (FileNotFoundException untarfe)
					{
						MessageBox.Show("Error: " + untarfe.Message + "\nYou are missing the ICSharp.ICSharpZipLib.dll file - Please find it in the backup directory and copy it to the bin directory", "Error in untaring", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}
					catch (Exception untare)
					{
						MessageBox.Show("Error: " + untare.Message, "Error in untaring", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}

					d = Convert.ToInt32(((percent / Convert.ToDouble(rar.records.Length)) * 100));
					if (user.Count != 0)
					{
						toolStripStatusLabel1.Text = dwnCounter + @"/" + user.Count + ": " + d.ToString() + "%";
					}
					else
					{
						toolStripStatusLabel1.Text = dwnCounter + @"/1" + ": " + d.ToString() + "%";
					}

					toolStripProgressBar1.Value = d;
					this.Refresh();
				}

				//Chris - you now have a list of folders (absolute paths) containing your results
				if (job.annotation == "")
				{
					doTheMerge(folders, tempDirName, 5000);
				}
				else
				{
					doTheMerge(folders, tempDirName, int.Parse(job.annotation));
				}
			}
		}

		private void doTheMerge(List<string> folders, string topLevelDir, int Nruns)
		{
			List<Output> output = new List<Output>();
			bool coordChecker = false;
			int coordRuns = 0;

			string resultsFile = topLevelDir + "\\results.csv";
			string coordsFile;
			StreamWriter resultsWriter = new StreamWriter(resultsFile);
			StreamWriter coordsWriter = null;

			resultsWriter.WriteLine("seed, tolerance, N_runs, N, before, after, evaluations, distance, runnumber");


			//Example merge - gets the input params and the values in CGM_solution.out and puts them in a csv file
			foreach (string s in folders)
			{
				coordsFile = topLevelDir + "\\coords.csv";

				string path = s + @"\Output\";	
				
                string[] files = Directory.GetFiles(path + "\\ZfuncMolecule\\", "CGM_Solution.out", SearchOption.AllDirectories);
				string[] filesCoord = Directory.GetFiles(path + "\\ZfuncMolecule\\", "CGM_EndCoord.coord", SearchOption.AllDirectories);
				string[] files1 = Directory.GetFiles(path + "\\ZfuncMolecule\\", "QN_Solution.out", SearchOption.AllDirectories);
				string[] filesCoord1 = Directory.GetFiles(path + "\\ZfuncMolecule\\", "QN_EndCoord.coord", SearchOption.AllDirectories);

				if (files.Length != 1 && files1.Length != 1)
				{
					MessageBox.Show("Error: Unable to find CGM_Solution.out or QN_Solution.out - exiting", "Error: Cannot find files", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}
				if (filesCoord.Length == 1 || filesCoord1.Length == 1)
				{
					coordChecker = true;

					if (!File.Exists(coordsFile))
					{
						coordsWriter = new StreamWriter(coordsFile);
						coordsWriter.WriteLine("runnumber, coords");
					}
					else if (File.Exists(coordsFile))
					{
						coordsWriter = new StreamWriter(coordsFile, true);
					}
					else
					{
						throw new Exception("We have an error");
					}
				}
				else if (filesCoord.Length != 1 && filesCoord1.Length != 1)
				{
					coordChecker = false;
				}

				string paramsFile = null; 
				string solutionFile = null;

				if (files.Length == 1)
				{
					paramsFile = path + "CGM_params.used";
					solutionFile = files[0];
				}
				else if (files1.Length == 1)
				{
					paramsFile = path + "QN_params.used";
					solutionFile = files1[0];
				}
				StreamReader paramsReader = new StreamReader(paramsFile);
				StreamReader solutionReader = new StreamReader(solutionFile);
				StreamReader coordReader = null;

				if (coordChecker)
				{
                    if (filesCoord.Length == 1)
                    {
                        string coordFile = filesCoord[0];
                        coordReader = new StreamReader(coordFile);
                    }
                    else if (filesCoord1.Length == 1)
                    {
                        string coordFile = filesCoord1[0];
                        coordReader = new StreamReader(coordFile);
                    }
				}

				//read the params file
				/*  structure is: 
					Seed               -1000
					Tolerance		   1E-50
					N_runs             3000
					N                  13
				 * */
				string seed = "";
				string tolerance = "";
				string N_runs = "";
				string N = "";

				#region readparams
				while (!paramsReader.EndOfStream)
				{
					string line = paramsReader.ReadLine();
					if (line.StartsWith("Seed"))
					{
						line = line.Replace("Seed", "");
						line = line.Trim();
						seed = line;
					}
					else if (line.StartsWith("Tolerance"))
					{
						line = line.Replace("Tolerance", "");
						line = line.Trim();
						tolerance = line;
					}
					else if (line.StartsWith("N_runs"))
					{
						line = line.Replace("N_runs", "");
						line = line.Trim();
						N_runs = line;
					}
					else if (line.StartsWith("N"))
					{
						line = line.Replace("N", "");
						line = line.Trim();
						N = line;
					}
				}
				#endregion

				paramsReader.Close();

				int numDim = int.Parse(N);
				coordRuns = int.Parse(N_runs);

				if (coordChecker)
				{
					#region coords

					string coordLine;
					string[] coordBits;
					while (!coordReader.EndOfStream)
					{
						try
						{
							coordLine = coordReader.ReadLine();
						}
						catch (System.IO.IOException ioe)
						{
							MessageBox.Show("Error in reading coords: " + "\n\t" + ioe.Message, "Error: IOException", MessageBoxButtons.OK, MessageBoxIcon.Error);
							return;
						}
						catch (System.OutOfMemoryException ome)
						{
							MessageBox.Show("Error in reading coords: " + "\n\t" + ome.Message, "Error: Out of Memory Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
							return;
						}

						try
						{
							coordBits = coordLine.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
						}
						catch (System.ArgumentOutOfRangeException aoute)
						{
							MessageBox.Show("Error in splitting coords: " + "\n\t" + aoute.Message, "Error: Arguemtn Out of Range Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
							return;
						}
						catch (System.ArgumentException ae)
						{
							MessageBox.Show("Error in splitting coords: " + "\n\t" + ae.Message, "Error: Argument Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
							return;
						}

						if (coordBits.Length == (numDim + 1))
						{
							string runnumber = coordBits[0];
							string[] coords = new string[numDim];
							string outline;

							for (int i = 1; i <= numDim; i++)
							{
								coords[i - 1] = coordBits[i];
							}

							//write out to csv
							outline = runnumber + ", ";
							for (int j = 0; j < numDim; j++)
							{
								outline += coords[j] + ", ";
							}

							coordsWriter.WriteLine(outline);
						}
						else
						{
							throw new Exception("Bits is the wrong length");
						}
					}

					coordReader.Close();
					coordsWriter.Close();

					#endregion
				}

				//read solution file
				//skip first 5 lines
				string line2;
				line2 = solutionReader.ReadLine();
				line2 = solutionReader.ReadLine();
				line2 = solutionReader.ReadLine();
				line2 = solutionReader.ReadLine();
				line2 = solutionReader.ReadLine();

				//6 to end are the interesting ones
				string interestingLine;
				string[] bits;
				bool endOfFile = false;
				while (!endOfFile)
				{
					try
					{
						interestingLine = solutionReader.ReadLine();
					}
					catch (System.IO.IOException ioe)
					{
						MessageBox.Show("Error in reading solution: " + "\n\t" + ioe.Message, "Error: IOException", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}
					catch (System.OutOfMemoryException ome)
					{
						MessageBox.Show("Error in reading solution: " + "\n\t" + ome.Message, "Error: Out of Memory Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}

					try
					{
						bits = interestingLine.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
					}
					catch (System.ArgumentOutOfRangeException aoute)
					{
						MessageBox.Show("Error in splitting solution: " + "\n\t" + aoute.Message, "Error: Arguemtn Out of Range Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}
					catch (System.ArgumentException ae)
					{
						MessageBox.Show("Error in splitting solution: " + "\n\t" + ae.Message, "Error: Argument Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
						unlock_Controls();
						return;
					}

					//bits will BeginInvoke 5 elements long
					//bits[0] is withoutLm, bits[1] is withLm, bits[2] is evaluations, bits[3] is distance, bits[4] is runnumber
					if (bits.Length == 6)
					{
						string before = bits[0];
						string after = bits[1];
						string evaluations = bits[2];
						string distance = bits[3];
						string runnumber = bits[4];
						string tol = bits[5];


						///////////////////////////////
						// Here!
						Output o;
            try
            {
              double fisse = double.Parse(after);
              o = new Output(int.Parse(seed), double.Parse(tolerance), int.Parse(N_runs), int.Parse(N), double.Parse(before), double.Parse(after), int.Parse(evaluations), double.Parse(distance), int.Parse(runnumber));
            }
            catch
            {
              o = new Output(int.Parse(seed), double.Parse(tolerance), int.Parse(N_runs), int.Parse(N), double.Parse(before), 9999.99, int.Parse(evaluations), double.Parse(distance), int.Parse(runnumber));
            }
						output.Add(o);
						///////////////////////////////

						//write out to csv
						//string outline = seed + ", " + tempStart + ", " + tempStep + ", " + tempStop + ", " + metropolis + ", " + N_md + ", " + N_mc + ", " + N_runs + ", " + N + ", " + nMin + ", " + without + ", " + with + ", " + bestCont + ", " + evaluations + ", " + distance + ", " + runnumber;
						//resultsWriter.WriteLine(outline);
					}
					else
					{
						endOfFile = true;

					}
				}

				solutionReader.Close();
			}

			/////////////////////////////
			// Sort the files!
			// output.Sort();
			/////////////////////////////

			foreach (Output o in output)
			{
				string outline = o.seed.ToString() + ", " + o.tol.ToString() + ", " + o.nRuns.ToString() + ", " + o.ndim.ToString() + ", " + o.before.ToString() + ", " + o.after.ToString() + ", " + o.evaluations.ToString() + ", " + o.distance.ToString() + ", " + o.runnumber.ToString();
				resultsWriter.WriteLine(outline);
			}

			resultsWriter.Close();
			outputLib.output results = null;

			if (radUser.Checked)
			{
				results = new outputLib.output(resultsFile, Nruns, int.Parse(lstJobs.Items[dwnCounter-1].SubItems[3].Text), coordRuns);
			}
			else if (radJobID.Checked)
			{
				results = new outputLib.output(resultsFile, Nruns, int.Parse(txtCutOff.Text), coordRuns);
			}

			try
			{
				results.LSRes();
			}
			catch (Exception lsre)
			{
				MessageBox.Show("Error: " + lsre.Message, "Error in extracting important info", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
		}
		#endregion

		#region Retrieval events
		private void butSaveDir_Click(object sender, EventArgs e)
		{
			if (folderBrowserDialog2.ShowDialog() == DialogResult.OK)
			{
				txtSaveDir.Text = folderBrowserDialog2.SelectedPath;
			}
		}
		
		private void radUser_CheckedChanged(object sender, EventArgs e)
		{
			userChanged();
		}

		private void userChanged()
		{
			if (radUser.Checked)
			{
				grpUser.Enabled = true;
				txtSaveDir.Enabled = true;
				grpJobID.Enabled = false;
				label10.Enabled = false;
				label11.Enabled = true;
				label12.Enabled = true;
				butSaveDir.Enabled = true;
			}
			else
			{
				grpUser.Enabled = false;
				lstJobs.Items.Clear();
				txtRetUser.Text = "";
				txtRetPass.Text = "";
				txtSaveDir.Enabled = true;
				grpJobID.Enabled = true;
				label10.Enabled = true;
				label11.Enabled = true;
				label12.Enabled = true;
				butSaveDir.Enabled = true;
			}
		}

		private void radJobID_CheckedChanged(object sender, EventArgs e)
		{
			userChanged();
		}

		private void txtRetUser_TextChanged(object sender, EventArgs e)
		{
			txtUsername.Text = txtRetUser.Text;
		}

		private void txtRetPass_TextChanged(object sender, EventArgs e)
		{
			txtPassword.Text = txtRetPass.Text;
		}

		private void butAddUser_Click(object sender, EventArgs e)
		{
			string auth = loginToGrid();
			if (auth == null)
			{
				return;
			}

			Mgsi.Application app;
			Mgsi.UserGroup userGroup;
			Mgsi.User[] UA;
			try
			{
				app = ud.getApplicationByName(auth, "Dev_HMC");
			}
			catch (Exception appe)
			{
				MessageBox.Show("Error: " + appe.Message, "Error in ud.getApplicationByName", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			try
			{
				userGroup = ud.getUserGroupByName(auth, "HMC_Users");
			}
			catch (Exception uge)
			{
				MessageBox.Show("Error: " + uge.Message, "Error in ud.getUserGroupByName", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			try
			{
				UA = ud.getUsersByUserGroup(auth, userGroup.user_group_gid);
			}
			catch (Exception ue)
			{
				MessageBox.Show("Error: " + ue.Message, "Error in ud.getUsersByUserGroup", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}

			string[] userGids = new string[UA.Length];
			for (int i = 0; i < UA.Length; i++)
			{
				userGids[i] = UA[i].user_gid;
			}

			//Mgsi.User griduser = ud.getUserByName(auth, txtRetUser.Text);
			UserJob userJob = new UserJob(ref lstJobs, ref user);

			//userJob.getUserInfo(auth, ud, griduser);
			try
			{
				userJob.getUserInfo(auth, ud, userGids, app);
			}
			catch (Exception uje)
			{
				MessageBox.Show("Error: " + uje.Message, "Error in getUserInfo", MessageBoxButtons.OK, MessageBoxIcon.Error);
				unlock_Controls();
				return;
			}
			//userJob.getUserInfo(auth, ud, app);
		}

		private void butRemoveUser_Click(object sender, EventArgs e)
		{
			int nremoved = 0;
			int whichone = 0;

			foreach (int index in lstJobs.SelectedIndices)
			{
				whichone = index - nremoved;
				try
				{
					user.Remove(user[whichone]);
				}
				catch (Exception exception)
				{
					MessageBox.Show("Error: " + exception.Message, "Error in removing jobs from List<> Object", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}
				nremoved++;
			}

			while (lstJobs.SelectedItems.Count != 0)
			{
				try
				{
					lstJobs.Items.RemoveAt(lstJobs.SelectedIndices[0]);
				}
				catch (Exception exception)
				{
					MessageBox.Show("Error: " + exception.Message, "Error in removing jobs from listview", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}
			}
		}

		private void lstJobs_SubItemClicked(object sender, ListViewEx.SubItemEventArgs e)
		{
			Editors = new Control[] { txtEditCutOff };
			if (e.SubItem == 3) // Password field
			{
				// the current value (text) of the subitem is ****, so we have to provide
				// the control with the actual text (that's been saved in the item's Tag property)
				if (e.Item.SubItems.Count != 4)
				{
					e.Item.SubItems.Add("");
				}
				else
				{
					// Do nothing
				}
				txtEditCutOff.Visible = true;
				try
				{
					lstJobs.StartEditing(Editors[0], e.Item, e.SubItem);
				}
				catch (Exception see)
				{
					MessageBox.Show("Error: " + see.Message, "Error in Editing the ListView Subitem", MessageBoxButtons.OK, MessageBoxIcon.Error);
					unlock_Controls();
					return;
				}
			}
		}

		private void lstJobs_SubItemEndEditing(object sender, ListViewEx.SubItemEndEditingEventArgs e)
		{
			if (e.SubItem == 3) // Password field
			{
				if (e.Cancel)
				{
					e.DisplayText = "";
				}
				else
				{
					e.DisplayText = txtEditCutOff.Text;
				}
			}
		}
		#endregion

		#region Misc
		private string loginToGrid()
		{
			try
			{
				toolStripStatusLabel1.Text = "Logging in to grid...";
				this.Refresh();
				auth = ud.login(txtUsername.Text, txtPassword.Text);
				toolStripStatusLabel1.Text = "Completed log into grid!";
				this.Refresh();
				return auth;
			}
			catch (Exception exp)
			{
				MessageBox.Show("Error logging in: " + exp.Message + "\nPlease Try Again", "Error Logging In", MessageBoxButtons.OK, MessageBoxIcon.Error);
				txtUsername.Text = "";
				txtPassword.Text = "";
				return null;
				//Environment.Exit(-1);
			}
		}

		private void logInTimer_Tick(object sender, EventArgs e)
		{
			try
			{
				auth = loginToGrid();
			}
			catch (Exception loge)
			{
				MessageBox.Show("Error: " + loge.Message, "Error logging in", MessageBoxButtons.OK, MessageBoxIcon.Error);
				txtUsername.Text = "";
				txtPassword.Text = "";
				return;
			}
		}

		private void log()
		{
			StreamWriter sw = new StreamWriter(Application.StartupPath + "\\input_log.log", false);

			if (radCGM.Checked)
			{
				sw.WriteLine("Alg: " + radCGM.Text);
			}
			else
			{
				sw.WriteLine("Alg: " + radQN.Text);
			}
			sw.WriteLine("Job_Name: " + txtJobName.Text);
			sw.WriteLine("Working_Folder: " + txtInputFolder.Text);
			sw.WriteLine();
			sw.WriteLine("-----------------------------------------");
			sw.WriteLine("Seed: " + txtSeed.Text);
			sw.WriteLine();

			if (radStepped.Checked)
			{
				sw.WriteLine("Start_Tol: " + txtTolStart.Text);
				sw.WriteLine("Step_Tol: " + txtTolStep.Text);
				sw.WriteLine("Stop_Tol: " + txtTolStop.Text);
				sw.WriteLine();
			}
			else
			{
				sw.WriteLine("Tol:");
				foreach (Object o in lstTol.Items)
				{
					sw.WriteLine("  " + o.ToString());
				}
				sw.WriteLine();
			}

			sw.WriteLine("Nruns: " + txtNruns.Text);
			sw.WriteLine("N: " + txtN.Text);
			sw.WriteLine();
			sw.WriteLine("ZMatrix: " + Path.GetFileName(txtZmat.Text));
			sw.WriteLine("Raw: " + Path.GetFileName(txtRaw.Text));
			sw.WriteLine("Number_Packages: " + txtNumPkg.Text);
			sw.WriteLine();
			sw.WriteLine("Username: " + txtUsername.Text);
			sw.WriteLine("-----------------------------------------");

			sw.Close();
		}
		#endregion

	}

	class MyPolicy : ICertificatePolicy
	{
		public bool CheckValidationResult(ServicePoint srvPoint, System.Security.Cryptography.X509Certificates.X509Certificate certificate, WebRequest request, int problem)
		{
			return problem == 0
				|| problem == -2146762487  // CertUNTRUSTEDROOT
				|| problem == -2146762481; // CertCN_NO_MATCH
		}
	}
}